#

| Chapter 45 Shell Programming for the Initiated |

## 45.8 Handling Signals to Child Processes

The Bourne shell trap command (44.12) controls what the shell does when it gets an interrupt or signal (from the kill (38.10) command, from a keyboard character like CTRL-c, and so on). To run an external command (1.10)- like an editor or a simple command such as sort-the shell starts a child process (38.3) (subprocess). If the program running in the child process wants to handle its own signals, the parent shell should probably pass signals on to the child process. For example, you might run vi as a child process and want to send a CTRL-c to stop vi from what it's doing, but not want the CTRL-c to kill the parent shell script.

When the parent process gets a signal, should it die or keep running? Should the child get the signal or not? The Bourne shell gives you a fair amount of flexibility in signal handling. The bad news is that most sh manual pages don't say much about this. And no manual page I've seen explains a useful choice: using the `:` (colon) operator (45.9) with trap. Table 45.1 shows your choices.

Table 45.1: trap Arguments (for Most Bourne Shells)
Argument | Effect
--- | ---
"" | Ignore signal, don't pass signal to child.
: | (undocumented) Ignore signal, pass signal to child.
"`command-line`" | Run command-line with variable and command substitution done when trap set; don't pass signal to child.
'`command-line`' | Run command-line with variable and command substitution done when trap executed; don't pass signal to child.
No argument | Reset signal handling to default (usually, parent terminates). Pass signal to child.

Because so much of this is undocumented, I won't try to give you "the answers" for how it should work with your shell. Instead, here are two shell scripts that let you experiment with your shell's signal handling. One script, named parent, starts the second script, child. The child script sets some traps, then starts sleep (40.2) so it'll be there when you send a signal. This lets you use CTRL-c or other interrupts, if parent is running in the foreground - or the kill command with signal numbers, if you've put parent in the background. You can edit the trap lines in the two scripts to test the setup you want to use.

Here's an example. I'll start parent in the background from the C shell, then send it a signal 1 ("hangup" signal):

    %1
    % parent &
    [1] 8669
    parent started
    child started. pid is 8671
    % kill -1 %1
    ./child: % 8671 Hangup
    child got a signal 1
    child exiting
    parent still running after child exited
    	...1000 seconds later...
    parent exiting
    [1]  + Done                 parent

Now, the scripts:

>     % cat parent
>     #!/bin/sh
>     echo parent started
>     trap "echo parent exiting; exit" 0
>     trap : 1                              # pass signal 1 to child but don't die
>     trap "" 2                             # ignore signal 2, block from child
>     trap "echo parent got signal 15" 15   # ignore signal 15, send to child
>                                           # die on other signals, send to child
>     child
>     echo parent still running after child exited
>     sleep 1000
>     % cat child
>     #! /bin/sh
>     echo child started. pid is $$.
>     trap 'echo child exiting; exit' 0
>     trap 'echo child got a signal 1' 1
>     trap '' 2       # ignore signal 2
>     trap 'echo child got a signal 3' 3
>     sleep 1000      # wait a long time for a signal

Even with this help, the way signal handling works might not be too clear. For more on signal handling, see a book that covers UNIX internals on your system.

- JP

45.7 The exec Command |  | 45.9 The Unappreciated Bourne Shell ":" Operator